package com.kjc.demo.basic.cpp;

import java.nio.ByteBuffer;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public class EncryptionMachine {
	/**
	 * 常量定义：每个密钥在加密机中的索引，在函数Update_ESAM_Key_And_MAC、Get_ESAM_MAC和Get_ESAM_Decrypt_Data作为Key_Index传入参数。
	 * */
	//	#define Init_SPECIFIC_CCK_INDEX		0	//0: 初始卡片主控密钥	已按统一代码分散
	private static final int Init_SPECIFIC_CCK_INDEX = 0;
	//	#define Init_SPECIFIC_ACK_INDEX		1	//1: 初始应用主控密钥	已按统一代码分散
	private static final int Init_SPECIFIC_ACK_INDEX = 1;
	//	#define OFFICIAL_AREA_CCK_INDEX		2	//2: 卡片主控密钥		已按区域代码分散
	private static final int OFFICIAL_AREA_CCK_INDEX = 2;
	//	#define OFFICIAL_AREA_ACK_INDEX		3	//3: 应用主控密钥		已按区域代码分散
	private static final int OFFICIAL_AREA_ACK_INDEX = 3;
	//	#define OFFICIAL_AREA_CMK_INDEX		4	//4: 卡片维护密钥		已按区域代码分散
	private static final int OFFICIAL_AREA_CMK_INDEX = 4;
	//	#define OFFICIAL_AREA_AMK_INDEX		5	//5: 应用维护密钥		已按区域代码分散
	private static final int OFFICIAL_AREA_AMK_INDEX = 5;
	//	#define OFFICIAL_AREA_RK1_INDEX		6	//6: 认证密钥			已按区域代码分散
	private static final int OFFICIAL_AREA_RK1_INDEX = 6;
	//	#define OFFICIAL_AREA_RK20_INDEX		7	//7: 加密密钥			已按区域代码分散
	private static final int OFFICIAL_AREA_RK20_INDEX = 7;
	//	#define OFFICIAL_AREA_RK21_INDEX		8	//8: 加密密钥			已按区域代码分散
	private static final int OFFICIAL_AREA_RK21_INDEX = 8;
	//	#define OFFICIAL_AREA_RK22_INDEX		9	//9: 加密密钥			已按区域代码分散
	private static final int OFFICIAL_AREA_RK22_INDEX = 9;
	//	#define TEST_CMK_INDEX				10	//10: 测试卡片维护密钥	已按统一代码分散
	private static final int TEST_CMK_INDEX = 10;
	//	#define TEST_AMK_INDEX				11	//11: 测试应用维护密钥	已按统一代码分散
	private static final int TEST_AMK_INDEX = 11;
	//	#define TEST_RK1_INDEX				12	//12: 测试认证密钥		已按统一代码分散
	private static final int TEST_RK1_INDEX = 12;
	//	#define TEST_RK20_INDEX				13	//13: 测试加密密钥		已按统一代码分散
	private static final int TEST_RK20_INDEX = 13;
	//	#define TEST_RK21_INDEX				14	//14: 测试加密密钥		已按统一代码分散
	private static final int TEST_RK21_INDEX = 14;
	//	#define TEST_RK22_INDEX				15	//15: 测试加密密钥		已按统一代码分散
	private static final int TEST_RK22_INDEX = 15;
	
	//	#define KEY_HEADER_CCK				"13000000"
	private static final int KEY_HEADER_CCK = 13000000;
	//	#define KEY_HEADER_ACK				"13000000"
	private static final int KEY_HEADER_ACK = 13000000;
	//	#define KEY_HEADER_CMK				"13010100"
	private static final int KEY_HEADER_CMK = 13010100;
	//	#define KEY_HEADER_AMK				"13010100"
	private static final int KEY_HEADER_AMK = 13010100;
	//	#define KEY_HEADER_RK1				"13010200"
	private static final int KEY_HEADER_RK1 = 13010200;
	//	#define KEY_HEADER_RK20				"13010300"
	private static final int KEY_HEADER_RK20 = 13010300;
	//	#define KEY_HEADER_RK21				"13010301"
	private static final int KEY_HEADER_RK21 = 13010301;
	//	#define KEY_HEADER_RK22				"13010302"
	private static final int KEY_HEADER_RK22 = 13010302;
	//	#define KEY_HEADER_UK				"13000100"
	private static final int KEY_HEADER_UK = 13000100;
	
	public interface EncryptionMachineLibrary extends Library {
        // DLL文件默认路径为项目根目录，若DLL文件存放在项目外，请使用绝对路径
		EncryptionMachineLibrary INSTANCE = (EncryptionMachineLibrary) Native.load((Platform.isWindows() ? "1748DevAPI" : "c"), EncryptionMachineLibrary.class);
        /**
         * 传输密钥初始化或明文装载工作密钥。该命令明文装载传输密钥，存放在硬件加密机中，返回是否成功装载，传输密钥索引大于200
         * @param
         * iKeyIndex	存储的传输密钥索引，索引值大于200 
         * szKeyVal[],	传输密钥明文，32字节数据，组成16进制16字节的密钥
         * */
        int KMS_Init_TransKey(int iKeyIndex, byte[] szKeyVal);
        
        /**
         * 装载工作密钥(传输密钥保护模式)。传入密钥密文信息，用指定密钥索引号的传输密钥解密恢复后，作为工作密钥存储在硬件加密机指定索引，传输密钥和导入密钥索引大于200。
         * iKeyIndex	存储工作密钥的索引
		 * iEncryptKeyLength	工作密钥密文长度(8*n, n>1)，1，2，3
		 * szEncryptKeyVal	工作密钥密文值
		 * iTransKeyIndex	传输密钥索引
		 * iKeyStartPos	用传输密钥对工作密钥密文解密后，从iKeyStartPos位置开始取16字节作为工作密钥明文
         * 
         * */
        int KMS_Load_Encrypt_Key(int iKeyIndex,int iEncryptKeyLength,byte[] szEncryptKeyVal,int iTransKeyIndex,int iKeyStartPos);
        
        /**
         * 删除指定索引下的密钥，密钥索引大于200
         * @param
         *  iKeyIndex	删除工作密钥的索引
         * */
        int KMS_Delete_Key(int iKeyIndex);
        
        /**
         * 工作密钥在Load_ESAM_Key导入加密机时，已经指定好该工作密钥的保护密钥。在执行Get_ESAM_Encrypt_Key指令时，
         * 找到该工作密钥的保护密钥，并对保护密钥分散，之后完成工作密钥的分散加密导出。
         * @param
         * Key_Index	要装载到ESAM模块的母密钥 Key1，该密钥先要经过一次分散得到Key1’，最终Key1’要装载到ESAM模块中
		 * div_factor	Key1的分散因子(8字节)
		 * Protect_Div_Factor	Key2的分散因子(8字节)
		 * Data_Length	填充数据长度
		 * Data	填充数据
		 * Encrypt_Key_Data	从加密机传出的发卡密文，最终传送给ESAM模块更新密钥
         * */
        void Get_ESAM_Encrypt_Key(int Key_Index,byte[] Div_Factor,byte[] Protect_Div_Factor,int Data_Length,byte[] Data,byte[] Encrypt_Key_Data);
        
        /**
         *  1、根据密钥索引号唯一确定该交易主密钥；
			2、根据分散因子对交易主密钥进行分散（支持1-3次），得到交易子密钥；  
			3、根据交易子密钥和初始向量生成MAC；
			@param
				Key_Index	用于产生过程密钥的主密钥的索引号
				div_factor	分散因子（分散次数 * 8个字节）
				Rand	初始向量
				MAC_Data_Len	生成MAC的数据长度
				MAC_Data	生成MAC的数据
				MAC	生成的MAC
         * */
        int Get_ESAM_MAC(int Key_Index,byte[] div_factor,byte[] Rand,int MAC_Data_Len, byte[] MAC_Data,byte[] MAC);
        
        void Get_RandomNum(byte[] randomNum);
        
	}
	
	public static void main(String[] args) {
		System.out.println("16进制转byte数组--------------------");
		System.out.println(hexStr2Byte("65C52936094FE4ECA279BFEA330B75D8"));
		int code = EncryptionMachineLibrary.INSTANCE.KMS_Init_TransKey(301, hexStr2Byte("65C52936094FE4ECA279BFEA330B75D8"));
		System.out.println("KMS_Init_TransKey"+code); 
		
		int loadCode = EncryptionMachineLibrary.INSTANCE.KMS_Load_Encrypt_Key(321,24,hexStr2Byte("1A1CBF37685F2D0B42F5883C57AC27E285250BCC1C6190BF"),301,4);
		System.out.println("KMS_Load_Encrypt_Key:"+loadCode);
		
		
//		int deletecode = EncryptionMachineLibrary.INSTANCE.KMS_Delete_Key(301);
//		System.out.println(deletecode);
		
		int maccode = EncryptionMachineLibrary.INSTANCE.Get_ESAM_MAC(301,intToByteArray(8),intToByteArray(100),10,intToByteArray(10000),intToByteArray(1));
		System.out.println(maccode);
		//		EncryptionMachineLibrary.INSTANCE.Get_RandomNum(intToByteArray(12));
//		EncryptionMachineLibrary.INSTANCE.Get_ESAM_Encrypt_Key(Init_SPECIFIC_CCK_INDEX,"12345678".getBytes(),"87654321".getBytes(),8,"1111111".getBytes(),"123456789".getBytes());
	}
	

	/** 
	 * Hex字符串转byte 
	 * @param inHex 待转换的Hex字符串 
	 * @return  转换后的byte 
	 */  
	public static byte hexToByte(String inHex){  
	   return (byte)Integer.parseInt(inHex,16);  
	} 
	
	public static int bytes2Int(byte[] bytes) {
		int result = 0;
		//将每个byte依次搬运到int相应的位置
		result = bytes[0] & 0xff;
		result = result << 8 | bytes[1] & 0xff;
		result = result << 8 | bytes[2] & 0xff;
		result = result << 8 | bytes[3] & 0xff;
		return result;
	}
	
	public static byte[] int2Bytes(int num) {
		byte[] bytes = new byte[4];
		//通过移位运算，截取低8位的方式，将int保存到byte数组
		bytes[0] = (byte)(num >>> 24);
		bytes[1] = (byte)(num >>> 16);
		bytes[2] = (byte)(num >>> 8);
		bytes[3] = (byte)num;
		return bytes;
	}
	
	public static byte[] hexStr2Byte(String hex) {
	    ByteBuffer bf = ByteBuffer.allocate(hex.length() / 2);
	    for (int i = 0; i < hex.length(); i++) {
	        String hexStr = hex.charAt(i) + "";
	        i++;
	        hexStr += hex.charAt(i);
	        byte b = (byte) Integer.parseInt(hexStr, 16);
	        bf.put(b);
	    }
	    return bf.array();
	}

	/**
     * int到byte[] 由高位到低位
     * @param i 需要转换为byte数组的整行值。
     * @return byte数组
     */
    public static byte[] intToByteArray(int i) {
        byte[] result = new byte[4];
        result[0] = (byte)((i >> 24) & 0xFF);
        result[1] = (byte)((i >> 16) & 0xFF);
        result[2] = (byte)((i >> 8) & 0xFF);
        result[3] = (byte)(i & 0xFF);
        return result;
    }
 
    /**
     * byte[]转int
     * @param bytes 需要转换成int的数组
     * @return int值
     */
    public static int byteArrayToInt(byte[] bytes) {
        int value=0;
        for(int i = 0; i < 4; i++) {
            int shift= (3-i) * 8;
            value +=(bytes[i] & 0xFF) << shift;
        }
        return value;
    }

}
